﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace FGK
{
    class Perspective : Kamera
    {
        static Random random = new Random();
        private float nearPlane;
        private float farPlane;
        private float fov;
        private MapaFotonow mapa;

        public float NearPlane
        {
            set { nearPlane = value; }
            get { return nearPlane; }
        }

        public float FarPlane
        {
            get { return farPlane; }
            set { farPlane = value; }
        }

        public float Fov
        {
            get { return fov; }
            set { fov = value; }
        }

        public Perspective()
        {
            this.Position = new Wektor(0.0f, 0.0f, 0.0f);
            this.Target = new Wektor(0.0f, 0.0f, 1.0f);
            this.nearPlane = 1.0f;
            this.farPlane = 1000;
            this.Up = new Wektor(0.0f, 1.0f, 0.0f);
        }

        public Perspective(float _near, float _far, float _fov, Wektor _position, Wektor _target, Stack<Obiekt> s, Stack<Swiatlo> sw, Obrazek o)
            : base(_position, _target, s, o, sw)
        {
            this.nearPlane = _near;
            this.farPlane = _far;
            this.fov = _fov;
            Target.normalize();
            mapa = new MapaFotonow();
        }
        /*
        private Promien analize(Promien r, int c)
        {
            if (r.Obiekt == null) return r;
            else if (r.Obiekt.material.Szklo != 1.0f)
            {
                int iter = 0;
                do
                {
                    if (r.Obiekt != null)
                    {
                        if (r.Obiekt.material.Szklo != 1.0f)
                        {
                            float deltaT, deltaS;
                            Wektor N = r.Obiekt.normalna(r.Koniec);
                            if (N.dot(r.Kierunek) < 0)
                            {
                                //z powietrza
                                deltaT = r.Obiekt.material.Szklo;
                                deltaS = 1.0f;
                            }
                            else
                            {
                                deltaS = r.Obiekt.material.Szklo;
                                deltaT = 1.0f;
                                N = -N;
                            }
                            float delta = deltaS / deltaT;
                            float cosI = N.dot(r.Kierunek);
                            float sinT2 = delta * delta * (1.0f - cosI * cosI);
                            if (sinT2 > 1.0)
                            {
                                return r;
                            }
                            if (deltaT == 0) return r;
                            if (1 - (deltaS * deltaS * (1 - Math.Pow(r.Kierunek.dot(N), 2))) / deltaT * deltaT < 0) return r;
                            Wektor R = ((delta * r.Kierunek - (delta + ((float)Math.Sqrt(1.0f - sinT2))) * N));
                            R.normalize();
                            Wektor p = r.Koniec + R * 0.0001f;
                            r = new Promien(p, R, r.Energia);
                            for (int z = 0; z < Obiekty.Count; z++)
                            {
                                Obiekty.ElementAt(z).IlePrzeciec(r);
                            }
                        }
                        else if (r.Obiekt.material.Lustro == 1.0f)
                        {
                            Wektor n = r.Obiekt.normalna(r.Koniec);
                            float cosI = n.dot(r.Kierunek);
                            Wektor k = r.Kierunek - 2.0f * cosI * n;
                            k.normalize();
                            Wektor p = r.Koniec + k * 0.0001f;
                            r = new Promien(p, k, r.Energia);
                            for (int z = 0; z < Obiekty.Count; z++)
                            {
                                Obiekty.ElementAt(z).IlePrzeciec(r);
                            }
                        }
                    }
                    iter++;
                } while (iter < c);
                return r;
            }
            else if (r.Obiekt.material.Lustro == 1.0f)
            {
                int iter = 0;
                while (iter < c)
                {
                    if (r.Obiekt != null)
                    {
                        if (r.Obiekt.material.Lustro == 1.0f)
                        {
                            Wektor n = r.Obiekt.normalna(r.Koniec);
                            float cosI = n.dot(r.Kierunek);
                            Wektor k = r.Kierunek - 2.0f * cosI * n;
                            k.normalize();
                            Wektor p = r.Koniec + k * 0.0001f;
                            r = new Promien(p, k, r.Energia);
                            for (int z = 0; z < Obiekty.Count; z++)
                            {
                                Obiekty.ElementAt(z).IlePrzeciec(r);
                            }
                        }
                        else if (r.Obiekt.material.Szklo != 1.0f)
                        {
                            float deltaT, deltaS;
                            Wektor N = r.Obiekt.normalna(r.Koniec);
                            if (N.dot(r.Kierunek) < 0)
                            {
                                //z powietrza
                                deltaT = r.Obiekt.material.Szklo;
                                deltaS = 1.0f;
                            }
                            else
                            {
                                deltaS = r.Obiekt.material.Szklo;
                                deltaT = 1.0f;
                                N = -N;
                            }
                            float delta = deltaS / deltaT;
                            float cosI = N.dot(r.Kierunek);
                            float sinT2 = delta * delta * (1.0f - cosI * cosI);
                            if (sinT2 > 1.0)
                            {
                                return r;
                            }
                            if (deltaT == 0) return r;
                            if (1 - (deltaS * deltaS * (1 - Math.Pow(r.Kierunek.dot(N), 2))) / deltaT * deltaT < 0) return r;
                            Wektor R = ((delta * r.Kierunek - (delta + ((float)Math.Sqrt(1.0f - sinT2))) * N));
                            R.normalize();
                            Wektor p = r.Koniec + R * 0.0001f;
                            r = new Promien(p, R, r.Energia);
                            for (int z = 0; z < Obiekty.Count; z++)
                            {
                                Obiekty.ElementAt(z).IlePrzeciec(r);
                            }
                        }
                    }
                    iter++;
                };
                return r;
            }
            else return r;
        } */
        private Promien analize(Promien r, int c)
        {
            //obsługa niczego
            if (r.Obiekt == null)
            {
                return r;
            }
                //obsługa szkła
            else if (r.Obiekt.material.Szklo != 1.0f)
            {
                float deltaT, deltaS;
                Wektor N = r.Obiekt.normalna(r.Koniec);
                if (N.dot(r.Kierunek) < 0)
                {
                    //z powietrza
                    deltaT = r.Obiekt.material.Szklo;
                    deltaS = 1.0f;
                }
                else
                {
                    deltaS = r.Obiekt.material.Szklo;
                    deltaT = 1.0f;
                    N = -N;
                }
                float delta = deltaS / deltaT;
                float cosI = N.dot(r.Kierunek);
                float sinT2 = delta * delta * (1.0f - cosI * cosI);
                if (sinT2 > 1.0)
                {
                    return r;
                }
                if (deltaT == 0) return r;
                if (1 - (deltaS * deltaS * (1 - Math.Pow(r.Kierunek.dot(N), 2))) / deltaT * deltaT < 0) return r;
                Wektor R = ((delta * r.Kierunek - (delta + ((float)Math.Sqrt(1.0f - sinT2))) * N));
                R.normalize();
                Wektor p = r.Koniec + R * 0.0001f;
                r = new Promien(p, R, r.Energia);
                for (int z = 0; z < Obiekty.Count; z++)
                {
                    Obiekty.ElementAt(z).IlePrzeciec(r);
                }
                if (r.Obiekt != null)
                {
                    if (((r.Obiekt.material.Szklo != 1.0f) || (r.Obiekt.material.Lustro != 0.0f)) && (c < 8)) r = analize(r, c + 1);
                }
                return r;

            }
            //obsługa lustra
            else if (r.Obiekt.material.Lustro != 0.0f)
            {
                Wektor n = r.Obiekt.normalna(r.Koniec);
                float cosI = n.dot(r.Kierunek);
                Wektor k = r.Kierunek - 2.0f*cosI * n;
                k.normalize();
                Wektor p = r.Koniec + k * 0.0001f;
                r = new Promien(p, k, r.Energia);
                for (int z = 0; z < Obiekty.Count; z++)
                {
                    Obiekty.ElementAt(z).IlePrzeciec(r);
                }
                if (r.Obiekt != null)
                {
                    if (((r.Obiekt.material.Szklo != 1.0f) || (r.Obiekt.material.Lustro != 0.0f)) && (c < 8)) r = analize(r, c + 1);
                }
                return r;

            }
            else return r;
        }
        
        private Kolor pobierzKolorPB(Promien r)
        {
            Kolor fKolor = new Kolor(0, 0, 0);
            if (r.Obiekt != null)
            {
                for (int s = 0; s < Swiatlo.Count; s++)
                {
                    Wektor kier = Swiatlo.ElementAt(s).Pozycja - r.Koniec;
                    float odleglosc = (Swiatlo.ElementAt(s).Pozycja - r.Koniec).length();
                    kier.normalize();
                    Promien ray = new Promien(r.Koniec + kier * 0.0001f, kier);
                    for (int k = 0; k < Obiekty.Count; k++)
                    {
                        Obiekty.ElementAt(k).IlePrzeciec(ray);
                    }
                    if (ray.Obiekt == null)
                    {
                        Wektor lightDir = Swiatlo.ElementAt(s).Pozycja - r.Koniec; 
                        float distance = lightDir.length(); 
                        distance = distance * distance;
                        lightDir.normalize();
                        float i = lightDir.dot(r.Obiekt.normalna(r.Koniec));
                        Kolor diffuse = Swiatlo.ElementAt(s).Kolor.mul(i  / distance) ;
                        diffuse = diffuse*r.Obiekt.material.Diffuse;
                        Wektor h = (lightDir + r.Kierunek);
                        h.normalize();
                        i = (float)Math.Pow(r.Obiekt.normalna(r.Koniec).dot(h), r.Obiekt.material.SpecularKoef);
                        Kolor Specular = r.Obiekt.material.Specular.mul(i  / distance);
                        Specular = Specular * Swiatlo.ElementAt(s).Kolor;
                        fKolor += diffuse + Specular;
                    }
                    else if ((ray.Koniec - r.Koniec).length() > odleglosc)
                    {
                        Wektor lightDir = Swiatlo.ElementAt(s).Pozycja - r.Koniec;
                        float distance = lightDir.length();
                        distance = distance * distance;
                        lightDir.normalize();
                        float i = lightDir.dot(r.Obiekt.normalna(r.Koniec));
                        Kolor diffuse = Swiatlo.ElementAt(s).Kolor.mul(i / distance);
                        diffuse = diffuse * r.Obiekt.material.Diffuse;
                        Wektor h = (lightDir + r.Kierunek);
                        h.normalize();
                        i = (float)Math.Pow(r.Obiekt.normalna(r.Koniec).dot(h), r.Obiekt.material.SpecularKoef);
                        Kolor Specular = r.Obiekt.material.Specular.mul(i / distance);
                        Specular = Specular * Swiatlo.ElementAt(s).Kolor;
                        fKolor += diffuse + Specular;
                    }

                }
                return fKolor;
            }
            else return new Kolor(0, 0, 0);
        }

        private Kolor pobierzKolor(Promien r)
        {
           Kolor direct = pobierzKolorP(r);
           Kolor indirect = pobierzKolorFs(r, 0.12f,0);
           //indirect = indirect * direct;
           Kolor kaustics = pobierzKolorFs(r, 0.01f,1);
           //kaustics = kaustics * direct;
           return (direct + indirect + kaustics);
           //return kaustics;

        }

        private Kolor pobierzKolorP(Promien r)
        {
            Kolor fKolor= new Kolor(0,0,0);
            if (r.Obiekt != null)
            {
                for (int s = 0; s < Swiatlo.Count; s++)
                {

                    Wektor kier1 = Swiatlo.ElementAt(s).Pozycja - r.Koniec;
                    float odleglosc = (Swiatlo.ElementAt(s).Pozycja - r.Koniec).length();
                    kier1.normalize();
                    Promien racl1 = new Promien(r.Koniec + kier1 * 0.0001f, kier1);
                    for (int k = 0; k < Obiekty.Count; k++)
                    {
                        Obiekty.ElementAt(k).IlePrzeciec(racl1);
                    }
                    if ((racl1.Obiekt != null))
                    {
                        float o2 = (racl1.Koniec - r.Koniec).length();
                        if (o2 < odleglosc) racl1 = analize(racl1, 0);
                    }
                    
                    //jeśli nic nie zakrywa obiektu
                    if ((racl1.Obiekt == null))
                    {

                        Wektor n = r.Obiekt.normalna(r.Koniec);
                        Wektor L = racl1.Kierunek;
                        Wektor R = 2.0f * (n * (L.dot(n))) - L;

                        Kolor tex = r.Obiekt.texDiff(r.Koniec);

                        Kolor ambient = Swiatlo.ElementAt(s).Kolor * r.Obiekt.material.Kolor;
                        Kolor diff = Swiatlo.ElementAt(s).Kolor * (tex.mul(L.dot(n)));
                        Kolor spec = Swiatlo.ElementAt(s).Kolor * r.Obiekt.material.Specular.mul((float)Math.Pow(R.dot(r.Kierunek), r.Obiekt.material.SpecularKoef));
                        fKolor = fKolor + ambient + diff + spec;
                        //fKolor = tex;
                    }
                    else if ((racl1.Koniec - r.Koniec).length() > odleglosc)
                    {

                        Wektor n = r.Obiekt.normalna(r.Koniec);
                        Wektor L = racl1.Kierunek;
                        Wektor R = 2.0f * (n * (L.dot(n))) - L;

                        Kolor tex = r.Obiekt.texDiff(r.Koniec);

                        Kolor ambient = Swiatlo.ElementAt(s).Kolor * r.Obiekt.material.Kolor;
                        Kolor diff = Swiatlo.ElementAt(s).Kolor * (tex.mul(L.dot(n)));
                        Kolor spec = Swiatlo.ElementAt(s).Kolor * r.Obiekt.material.Specular.mul((float)Math.Pow(R.dot(r.Kierunek), r.Obiekt.material.SpecularKoef));
                        fKolor = fKolor + ambient + diff + spec;
                        //fKolor = tex;
                    }
                }
                return fKolor;
            }
            else
            {
                return new Kolor(0,0,0);
            }
        }

        private void uwolnijfotony(int ile, int odbicia)
        {
            for (int j = 0; j < Swiatlo.Count; j++)
            {
                for (int i = 0; i < ile/Swiatlo.Count; i++)
                {
                    Console.Write("\r" + "* propagacja fotonów " + (float)(i+1)*(j+1) / (float)ile * 100.0f + "%       ");
                    //określenie parametrów promienia po którym poruszać się będzie foton
                    Wektor start = Swiatlo.ElementAt(j).Pozycja;
                    Wektor kierunek = new Wektor(1, 1, 1);
                    //Random random = new Random();
                    float x, y, z;
                    bool zdechl=false;
                    int iterator=0;
                    do
                    {
                        x = (float)random.Next(-100, 100);
                        y = (float)random.Next(-100, 100);
                        z = (float)random.Next(-100, 100);
                        kierunek = new Wektor(x, y, z);
                    } while (kierunek.length()==0);
                    //start promienia
                    kierunek.normalize();
                    Promien r = new Promien(start, kierunek, Swiatlo.ElementAt(0).Kolor); 
                    //śledzenie
                    do
                    {
                        //warunek wyjścia
                        if (iterator == odbicia) zdechl = true;
                        else
                        {
                            //zwiekszam licznik odbic
                            iterator++;
                            //sprawdzamy kolizje
                            for (int k = 0; k < Obiekty.Count; k++)
                            {
                                //z czym się zderzył
                                Obiekty.ElementAt(k).IlePrzeciec(r); 
                                //jak trafił na zwierciadło/szkło
                                r = analize(r, 0);
                            }
                            //uciekl==zdechł
                            if (r.Obiekt == null) zdechl = true;
                            else
                            {
                                //dodajmy go do listy
                                mapa.add(new Foton(r.Koniec,r.Kierunek,r.Energia, Swiatlo.ElementAt(j).Intensywnosc));
                                //może zdechnie?
                                if (random.Next(0, 100) > 50) zdechl = true;
                                //jak nie
                                else
                                {
                                    //kierunek
                                    do
                                    {
                                        x = (float)random.Next(-100, 100);
                                        y = (float)random.Next(-100, 100);
                                        z = (float)random.Next(-100, 100);
                                        kierunek = new Wektor(x, y, z);
                                    } while(kierunek.length()==0);
                                    kierunek.normalize();
                                    if (kierunek.dot(r.Obiekt.normalna(r.Koniec)) < 0) kierunek *= -1;
                                    //energia
                                    Kolor kolor = r.Obiekt.texDiff(r.Koniec);
                                    float sr = (kolor.R + kolor.G + kolor.B) / 3;
                                    Kolor energia = new Kolor(r.Energia.R * kolor.R / sr, r.Energia.G * kolor.G / sr, r.Energia.B * kolor.B / sr);
                                    //promien
                                    r = new Promien(r.Koniec+kierunek*0.0001f, kierunek, energia);
                                }
                            }

                        }
                    } while (!zdechl);
                }
            }
            Console.WriteLine(" ");
        }

        private void uwolnijfotonyK(int ile, int odbicia)
        {
            for (int j = 0; j < Swiatlo.Count; j++)
            {
                for (int i = 0; i < ile / Swiatlo.Count; i++)
                {
                    Console.Write("\r" + "* wyostrzam kaustykę fotonów " + (float)(i + 1) * (j + 1) / (float)ile * 100.0f + "%       ");
                    //określenie parametrów promienia po którym poruszać się będzie foton
                    Wektor start = Swiatlo.ElementAt(j).Pozycja;
                    Wektor kierunek = new Wektor(1, 1, 1);
                    //Random random = new Random();
                    float x, y, z;
                    bool zdechl = false;
                    int iterator = 0;
                    do
                    {
                        x = (float)random.Next(-100, 100);
                        y = (float)random.Next(-100, 100);
                        z = (float)random.Next(-100, 100);
                        kierunek = new Wektor(x, y, z);
                    } while (kierunek.length() == 0);
                    //start promienia
                    kierunek.normalize();
                    Promien r = new Promien(start, kierunek, Swiatlo.ElementAt(0).Kolor);
                    Promien r2 = new Promien(start, kierunek, Swiatlo.ElementAt(0).Kolor);
                    bool zalamany = false;
                    //śledzenie
                    do
                    {
                        //warunek wyjścia
                        if (iterator == odbicia) zdechl = true;
                        else
                        {
                            //zwiekszam licznik odbic
                            iterator++;
                            //sprawdzamy kolizje
                            for (int k = 0; k < Obiekty.Count; k++)
                            {
                                //z czym się zderzył
                                Obiekty.ElementAt(k).IlePrzeciec(r);
                                //jak trafił na zwierciadło/szkło
                                r = analize(r, 0);
                            }
                            if ((r.Kierunek != r2.Kierunek) || (r.Start != r2.Start)) zalamany = true;
                            //uciekl==zdechł
                            if (r.Obiekt == null) zdechl = true;
                            else
                            {
                                //dodajmy go do listy
                                if(zalamany) mapa.add2(new Foton(r.Koniec, r.Kierunek, r.Energia, Swiatlo.ElementAt(j).Intensywnosc));
                                //może zdechnie?
                                if (random.Next(0, 100) > 50) zdechl = true;
                                //jak nie
                                else
                                {
                                    //kierunek
                                    do
                                    {
                                        x = (float)random.Next(-100, 100);
                                        y = (float)random.Next(-100, 100);
                                        z = (float)random.Next(-100, 100);
                                        kierunek = new Wektor(x, y, z);
                                    } while (kierunek.length() == 0);
                                    kierunek.normalize();
                                    if (kierunek.dot(r.Obiekt.normalna(r.Koniec)) < 0) kierunek *= -1;
                                    //energia
                                    Kolor kolor = r.Obiekt.texDiff(r.Koniec);
                                    float sr = (kolor.R + kolor.G + kolor.B) / 3;
                                    Kolor energia = new Kolor(r.Energia.R * kolor.R / sr, r.Energia.G * kolor.G / sr, r.Energia.B * kolor.B / sr);
                                    //promien
                                    Wektor starter = r.Koniec + kierunek * 0.0001f;
                                    r = new Promien(starter, kierunek, energia);
                                    r2 = new Promien(starter, kierunek, energia);
                                }
                            }

                        }
                    } while (!zdechl);
                }
            }
            Console.WriteLine("  ");
        }

        private void uwolnijfotonyKs(int ile, int odbicia)
        {
            for (int j = 0; j < Swiatlo.Count; j++)
            {
                for (int obj = 0; obj < Obiekty.Count; obj++)
                {
                    if ((Obiekty.ElementAt(obj).material.Szklo != 1.0f) || (Obiekty.ElementAt(obj).material.Lustro == 1.0f))
                    {
                        float maxX, minX, maxY, minY, maxZ, minZ;
                        minX = Obiekty.ElementAt(obj).brylaOtaczajaca()[0].X;
                        maxX = Obiekty.ElementAt(obj).brylaOtaczajaca()[1].X;
                        minY = Obiekty.ElementAt(obj).brylaOtaczajaca()[0].Y;
                        maxY = Obiekty.ElementAt(obj).brylaOtaczajaca()[1].Y;
                        minZ = Obiekty.ElementAt(obj).brylaOtaczajaca()[0].Z;
                        maxZ = Obiekty.ElementAt(obj).brylaOtaczajaca()[1].Z;
                        //Console.WriteLine(Obiekty.ElementAt(obj).brylaOtaczajaca()[0]);
                        //Console.WriteLine(Obiekty.ElementAt(obj).brylaOtaczajaca()[1]);
                        for (int i = 0; i < ile / Swiatlo.Count; i++)
                        {
                            Console.Write("\r" + "* wyostrzam kaustykę dla obiektu " + obj + ": " + (float)(i + 1) * (j + 1) / (float)ile * 100.0f + "%       ");
                            //określenie parametrów promienia po którym poruszać się będzie foton
                            Wektor start = Swiatlo.ElementAt(j).Pozycja;
                            Wektor kierunek = new Wektor(1, 1, 1);
                            //Random random = new Random();
                            float x, y, z;
                            bool zdechl = false;
                            int iterator = 0;
                            do
                            {
                                x = (float)((maxX-minX)*random.NextDouble()+minX);
                                y = (float)((maxY-minY)*random.NextDouble()+minY);
                                z = (float)((maxZ-minZ)*random.NextDouble()+minZ);
                                kierunek = new Wektor(x-start.X, y-start.Y, z-start.Z);
                            } while (kierunek.length() == 0);
                            //start promienia
                            kierunek.normalize();
                            Promien r = new Promien(start, kierunek, Swiatlo.ElementAt(0).Kolor);
                            Promien r2 = new Promien(start, kierunek, Swiatlo.ElementAt(0).Kolor);
                            bool zalamany = false;
                            //śledzenie
                            do
                            {
                                //warunek wyjścia
                                if (iterator == odbicia) zdechl = true;
                                else
                                {
                                    //zwiekszam licznik odbic
                                    iterator++;
                                    //sprawdzamy kolizje
                                    for (int k = 0; k < Obiekty.Count; k++)
                                    {
                                        //z czym się zderzył
                                        Obiekty.ElementAt(k).IlePrzeciec(r);
                                        //jak trafił na zwierciadło/szkło
                                        r = analize(r, 0);
                                    }
                                    if ((r.Kierunek != r2.Kierunek) || (r.Start != r2.Start)) zalamany = true;
                                    //uciekl==zdechł
                                    if (r.Obiekt == null) zdechl = true;
                                    else
                                    {
                                        //dodajmy go do listy
                                        if (zalamany) mapa.add2(new Foton(r.Koniec, r.Kierunek, r.Energia, Swiatlo.ElementAt(j).Intensywnosc));
                                        //może zdechnie?
                                        if (random.Next(0, 100) > 50) zdechl = true;
                                        //jak nie
                                        else
                                        {
                                            //kierunek
                                            do
                                            {
                                                x = (float)random.Next(-100, 100);
                                                y = (float)random.Next(-100, 100);
                                                z = (float)random.Next(-100, 100);
                                                kierunek = new Wektor(x, y, z);
                                            } while (kierunek.length() == 0);
                                            kierunek.normalize();
                                            if (kierunek.dot(r.Obiekt.normalna(r.Koniec)) < 0) kierunek *= -1;
                                            //energia
                                            Kolor kolor = r.Obiekt.texDiff(r.Koniec);
                                            float sr = (kolor.R + kolor.G + kolor.B) / 3;
                                            Kolor energia = new Kolor(r.Energia.R * kolor.R / sr, r.Energia.G * kolor.G / sr, r.Energia.B * kolor.B / sr);
                                            //promien
                                            Wektor starter = r.Koniec + kierunek * 0.0001f;
                                            r = new Promien(starter, kierunek, energia);
                                            r2 = new Promien(starter, kierunek, energia);
                                        }
                                    }

                                }
                            } while (!zdechl);
                        }
                    }
                }
                }
                Console.WriteLine("  ");
            }

        private Kolor pobierzKolorF(Promien r, float poszukiwania)
        {
            float ile = 0;
            //jeśli trafił
            if (r.Obiekt != null)
            {
                if (r.Obiekt.material.Lustro == 1.0f) return new Kolor(0, 0, 0);
                else if (r.Obiekt.material.Szklo != 1.0f) return new Kolor(0, 0, 0);
                else
                {
                    float FinalKolorR=0, FinalKolorG=0, FinalKolorB=0;
                    for (int i = 0; i < mapa.fotony.Count; i++)
                    {
                        Wektor odleglosc = mapa.fotony.ElementAt(i).Pozycja - r.Koniec;
                        if((odleglosc.length()<=poszukiwania)) {
                            FinalKolorR+=mapa.fotony.ElementAt(i).Energia.R;
                            FinalKolorG+=mapa.fotony.ElementAt(i).Energia.G;
                            FinalKolorB+=mapa.fotony.ElementAt(i).Energia.B;
                            ile+=1;
                        }
                    }
                    return new Kolor(FinalKolorR/ile, FinalKolorG/ile, FinalKolorB/ile);
                }
            }
                //a jak nie
            else return new Kolor(0, 0, 0);
        }

        private Kolor pobierzKolorFs(Promien r, float poszukiwania, int flag)
        {
            //jeśli trafił
            if (r.Obiekt != null)
            {
                if (r.Obiekt.material.Lustro == 1.0f) return new Kolor(0, 0, 0);
                else if (r.Obiekt.material.Szklo != 1.0f) return new Kolor(0, 0, 0);
                else
                {
                    if (flag == 0) return mapa.GetKolor(r.Koniec, poszukiwania);
                    else return mapa.GetKaustyka(r.Koniec, poszukiwania);
                }
            }
            //a jak nie
            else return new Kolor(0, 0, 0);
        }

        public override void render_scene()
        { 
            Console.WriteLine("Kamera perspektywiczna");
            Kolor tlo = new Kolor(0.0f,0.0f,0.0f);

            //ustalanie rozmiarów pixela
            float szerokoscPixela = 4.0f / (float)Obraz.Szerokosc;
            float wysokoscPixela = 4.0f / (float)Obraz.Wysokosc;
            //fotony


            uwolnijfotony(100000, 5);
            uwolnijfotonyKs(8000, 2);
            mapa.UstawRoot();
            //test ile
            Console.WriteLine("  * zapisano "+mapa.fotony.Count+" fotonów w mapie");
            Console.WriteLine("  * zapisano " + mapa.kaustyka.Count + " fotonów w mapie kaustyki");
            //algorytm
            for (int i = 0; i < Obraz.Szerokosc; i++)
            {
                Console.Write("\r"+ "* renderowanie "+(float)i/(float)Obraz.Szerokosc*100.0f + "%       ");
                for (int j = 0; j < Obraz.Wysokosc; j++)
                {
                    //promienie
                    float alpha = -2.0f + i*szerokoscPixela;
                    float beta = 2.0f - j*wysokoscPixela;
                    Wektor kierunkowy1 = new Wektor(Position.X + alpha, Position.Y + beta, Position.Z - fov) - Position; kierunkowy1.normalize();
                    Promien ray = new Promien(Position, kierunkowy1);
                    Wektor kierunkowy2 = new Wektor(Position.X + alpha + szerokoscPixela, Position.Y + beta, Position.Z - fov) - Position; kierunkowy2.normalize();
                    Promien ray2 = new Promien(Position, kierunkowy2);
                    Wektor kierunkowy3 = new Wektor(Position.X + alpha + szerokoscPixela, Position.Y + beta + wysokoscPixela, Position.Z - fov) - Position; kierunkowy3.normalize();
                    Promien ray3 = new Promien(Position, kierunkowy3);
                    Wektor kierunkowy4 = new Wektor(Position.X + alpha, Position.Y + beta + wysokoscPixela, Position.Z - fov) - Position; kierunkowy4.normalize();
                    Promien ray4 = new Promien(Position, kierunkowy4);
                    Wektor kierunkowy5 = new Wektor(Position.X + alpha+szerokoscPixela/2, Position.Y + beta+wysokoscPixela/2, Position.Z - fov) - Position; kierunkowy5.normalize();
                    Promien ray5 = new Promien(Position, kierunkowy5);
                    //kolizje z obiektami
                    for (int k = 0; k < Obiekty.Count; k++)
                    {
                        Obiekty.ElementAt(k).IlePrzeciec(ray); ray=analize(ray,6);
                        Obiekty.ElementAt(k).IlePrzeciec(ray2); ray2=analize(ray2,6);
                        Obiekty.ElementAt(k).IlePrzeciec(ray3); ray3=analize(ray3,6);
                        Obiekty.ElementAt(k).IlePrzeciec(ray4); ray4=analize(ray4,6);
                        Obiekty.ElementAt(k).IlePrzeciec(ray5); ray5 = analize(ray5,6);
                    }
                    //wyciągam kolor
                    float finalkolorR = 0;
                    float finalkolorG = 0;
                    float finalkolorB = 0;
                    float rp = 0.03f;
                    //Kolor ray1k = pobierzKolor(ray);
                    //Kolor ray2k = pobierzKolor(ray2);
                    //Kolor ray3k = pobierzKolor(ray3);
                    //Kolor ray4k = pobierzKolor(ray4);
                    //Kolor ray5k = pobierzKolor(ray5);
                    //finalkolorR = (ray1k.R + ray2k.R + ray3k.R + ray4k.R + ray5k.R) / 5;
                    //finalkolorG = (ray1k.G + ray2k.G + ray3k.G + ray4k.G + ray5k.G) / 5;
                    //finalkolorB = (ray1k.B + ray2k.B + ray3k.B + ray4k.B + ray5k.B) / 5;
                    
                    finalkolorR = (pobierzKolor(ray).R);
                    finalkolorG = (pobierzKolor(ray).G);
                    finalkolorB = (pobierzKolor(ray).B);
                    //dodaje pixel
                    Obraz.setPixel(i, j, new Kolor(finalkolorR,finalkolorG,finalkolorB).toUint()); 
                }
            }
            //rasteryzuj
            Obraz.rasterize();
        }
        
    }
}
